/*jslint newcap:true, browser: true, devel: true, bitwise: true, white: true, plusplus: true, forin:true, nomen:true */
/*global $:true, define:true */

/**
 * @module Test
 */

define(['WID/Test/Matcher'],function(Matcher) {
"use strict";

/** 
 * 
 * @class toThrow
 * @constructor
 */
function toThrow() {
	this.LastException = null;
	this.Negation = null;
	this.LastMessage = null;
} var extend = Object.create(Matcher.prototype);extend.constructor = toThrow;

extend.getName = function() {
	return 'toThrow';
};

extend.match = function(target, negation, exceptionClassName) {
	this.clear();
	try {
		target.call();
		return this.matchNothingThrow(negation);
	} catch (e) {
		return this.matchException(e,negation,exceptionClassName);
	}
};

extend.matchNothingThrow = function(negation) {
		if (negation) {
			return true;
		}
		return false;	
};

extend.matchException = function(exception, negation, exceptionClassName) {
		this.LastException = exception;
		if (negation) {
			return false;
		}
		if (exception instanceof exceptionClassName) {
			return this;
		}
};

extend.withMessage = function(message) {
	var e = this.LastException;
	if (!e) {
		return false;
	}
		
	if ((this.Negation)?e.message === message:e.message !== message) {
		this.LastMessage = message;
		return false;
	}
	return true;
};

extend.getInfo = function(target, negation, exceptionClassName) {
	var info = Matcher.prototype.getInfo.call(this,target,negation,exceptionClassName);
		if (negation) {
			info += 'throw but throw '+this.LastException.constructor.name;
		} else {
			if (this.LastException) {
				if (this.LastMessage) {
					info += 'to throw '+exceptionClassName+' with message: '+
						this.LastMessage+' but message is '+this.LastException.getMessage();
				} else {
					info += 'to throw '+exceptionClassName+' but throw '+this.LastException.constructor.name;
				}
			} else {
				info += 'to throw '+exceptionClassName+' but nothing throw';
			}
		}
		return info;
};

extend.clear = function() {
	this.Negation = false;
	this.LastException = null;
	this.Message = '';
};

Object.defineProperties(extend,{
	not: {
		get: function() {
			this.Negation = !this.Negation;
			return this;
		}
	}
});

toThrow.prototype = extend;
return toThrow;
});
